package com.ansion.log;

import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * @author john on 2020/11/6.
 * @version 1.0
 * @desc
 */
public abstract class Logger {
    protected int logLevel = VLog.DEBUG;
    protected boolean fullClassName = false;
    protected boolean messageFilter = false;

    public Logger setLogLevel(int level) {
        logLevel = level;
        return this;
    }

    public Logger enableFullClassName(boolean enable) {
        fullClassName = enable;
        return this;
    }

    public Logger enableMessageFilter(boolean enable) {
        messageFilter = enable;
        return this;
    }

    @SuppressWarnings("BooleanMethodIsAlwaysInverted")
    public boolean showLog(int level, String tag) {
        if (level >= logLevel) {
            return true;
        }

        try {
            return Log.isLoggable(VLog.TAG, level);
        } catch (Exception e) {
            log(null, 1, VLog.ERROR, VLog.TAG, null, "please check the log tag length [%s]", tag);
        }

        return false;
    }

    public void flush() {
        // nothing to do by default
    }

    public abstract void log(Throwable callerStack, int callerStackIndex, int level, @NonNull String tag,
                             @Nullable Throwable tr, @Nullable String msg, Object... args);

    protected void appendMessage(Throwable callerStack, int callerStackIndex,
                                 StringBuilder sb, @Nullable Throwable t, @Nullable String msg, Object... args) {
//        String callerClassName = "";
//        String callerMethodName = "";
//        if (callerStack != null) {
//            StackTraceElement[] elements = callerStack.getStackTrace();
//            if (elements.length > callerStackIndex) {
//                StackTraceElement callerElement = elements[callerStackIndex];
//                callerClassName = callerElement.getClassName();
//                if (!fullClassName) {
//                    int index = callerClassName.lastIndexOf('.');
//                    if (index > 0 && index + 1 < callerClassName.length()) {
//                        callerClassName = callerClassName.substring(index + 1);
//                    }
//                }
//                callerMethodName = callerElement.getMethodName();
//            }
//        }
        if (msg != null && args != null && args.length > 0) {
            try {
                msg = VLog.safeFormat(msg, args);
            } catch (Exception e) {
                if (throwLogError()) {
                    throw new RuntimeException(e.toString(), callerStack);
                } else {
                    sb.append("TAG_LOG_ERROR").append(' ').append(e.toString()).append('\n');
                    sb.append(Log.getStackTraceString(callerStack));
                }
            }
        }
        if (msg != null && messageFilter) {
            String critical = LogFilter.criticalMsg(msg);
            if (!TextUtils.isEmpty(critical)) {
                msg = critical;
            }
        }
        String threadName = Thread.currentThread().getName();
        threadName = TextUtils.isEmpty(threadName) ? "" : threadName;
        if (!TextUtils.isEmpty(threadName)) {
            sb.append("(tn:").append(threadName).append(")");
        }
//        if (!TextUtils.isEmpty(callerClassName) && !TextUtils.isEmpty(callerMethodName)) {
//            sb.append("[").append(callerClassName).append('#').append(callerMethodName).append("] ");
//        }
        if (msg != null) {
            sb.append(msg);
        }
        if (t != null) {
            sb.append('\n').append(Log.getStackTraceString(t));
        }
    }


    protected boolean throwLogError() {
        return false;
    }

    protected char logLevelStr(int level) {
        switch (level) {
            case VLog.VERBOSE:
                return 'V';
            case VLog.DEBUG:
                return 'D';
            case VLog.INFO:
                return 'I';
            case VLog.WARN:
                return 'W';
            case VLog.ERROR:
                return 'E';
        }
        return 'U';
    }
}
